﻿using System;

namespace BizElements.BusinessLayer
{
    /// <summary>
    /// Provides common security and business rule checks and descriptions.
    /// </summary>
    [Obsolete("This class is obsolete and will be removed in a future release. Use SecurityUtil class instead.")]
    public static class GrantHelper
    {
        #region EnforceRules.

        /// <summary>
        /// Throws <see cref="BrokenRuleException"/> if the provided collection has broken rules.
        /// </summary>
        /// <param name="rules">Rules to evaluate.</param>
        [Obsolete]
        public static void EnforceRules(BusinessRuleCollection rules)
        {
            if (rules.HasBrokenRules)
                throw new BrokenRuleException(rules);
        }

        /// <summary>
        /// Throws <see cref="BrokenRuleException"/> if the provided method return a collection with broken rules.
        /// </summary>
        /// <param name="condition">If <b>true</b> the provided method is executed and rules are evaluate.</param>
        /// <param name="grantMethod">A method which checks the rules for the specified actor.</param>
        /// <param name="actor">Actor fow which the rules are to be evaluated if <b>condition</b> parameter is set to <b>true</b>.</param>
        public static void EnforceRules(bool condition, Delegates.Function<BusinessRuleCollection, IActor> grantMethod, IActor actor)
        {
            if (condition)
            {
                BusinessRuleCollection rules = grantMethod(actor);
                if (rules.HasBrokenRules)
                    throw new BrokenRuleException(rules);
            }
        }

        #endregion

        #region CheckPermission.

        /// <summary>Specifies the key in a <see cref="ITextSource"/> which should contain default "permission denied" message.
        /// Default is <b>_GrantHelper_PermissionDenied</b>.</summary>
        /// <value>"_GrantHelper_PermissionDenied"</value>
        public static string PermissionDeniedDescriptionKey = "_GrantHelper_PermissionDenied";

        /// <summary>
        /// Gets description which is used if a <see cref="ITextSource"/> doesn't contain the <b>GrantHelper_PermissionDenied</b> key.
        /// </summary>
        /// <value>English: "You don't have the required permission to execute the requested action."</value>
        public static string DefaultPermissionDeniedDescription
        {
            get { return Messages.GrantHelper_DefaultPermissionDeniedDescription; }
        }

        /// <summary>
        /// Gets the default "permission denied" message from the specified source.
        /// </summary>
        /// <param name="ruleDescriptions">Message source which contains the string with the key specified in <see cref="PermissionDeniedDescriptionKey"/>.</param>
        /// <returns>A message with the <see cref="PermissionDeniedDescriptionKey"/> key or <see cref="DefaultPermissionDeniedDescription"/> if not found.</returns>
        public static string GetPermissionDeniedDescription(ITextSource ruleDescriptions)
        {
            string description = ruleDescriptions.GetString(PermissionDeniedDescriptionKey);
            return string.IsNullOrEmpty(description) ? DefaultPermissionDeniedDescription : description;
        }

        /// <summary>
        /// Check if actor has the specified permission.
        /// </summary>
        /// <param name="actor">Action initiator which should contains the specified permission.</param>
        /// <param name="permissionId">The ID of the action that the actor is trying to initiate.</param>
        /// <param name="ruleKey">Optional <see cref="BusinessRule.Name"/>.</param>
        /// <param name="ruleDescriptions">Message source which contains the description of the specified rules.
        /// If a string with <b>ruleKey</b> is not found, a default description is used.</param>
        /// <returns>Empty collection if actor has permission; otherwise a collection with one broken rule.</returns>
        public static BusinessRuleCollection CheckPermission(IActor actor, object permissionId, string ruleKey, ITextSource ruleDescriptions)
        {
            string description = null;
            if (!string.IsNullOrEmpty(ruleKey))
                description = ruleDescriptions.GetString(ruleKey);
            if (string.IsNullOrEmpty(description))
                description = GetPermissionDeniedDescription(ruleDescriptions);

            BusinessRuleCollection permissions = new BusinessRuleCollection();
            permissions.Add(new BusinessRule(ruleKey, actor.HasPermission(permissionId), description));
            return permissions.GetBrokenRules();
        }

        /// <summary>
        /// Checks whether actor has any of the specified permissions.
        /// </summary>
        /// <param name="actor">Action initiator which should contains the specified permission.</param>
        /// <param name="ruleKey">Optional <see cref="BusinessRule.Name"/>.</param>
        /// <param name="ruleDescriptions">Message source which contains the description of the specified rules.
        /// If a string with <b>ruleKey</b> is not found, a default description is used.</param>
        /// <param name="permissionIDs">IDs of actions that the actor is trying to initiate.</param>
        /// <returns>Empty collection if actor has permission; otherwise a collection with one broken rule.</returns>
        public static BusinessRuleCollection CheckAnyPermission(IActor actor, string ruleKey, ITextSource ruleDescriptions, params object[] permissionIDs)
        {
            string description = null;
            if (!string.IsNullOrEmpty(ruleKey))
                description = ruleDescriptions.GetString(ruleKey);
            if (string.IsNullOrEmpty(description))
                description = GetPermissionDeniedDescription(ruleDescriptions);

            BusinessRuleCollection permissions = new BusinessRuleCollection();
            bool hasPermission = false;
            foreach (object permId in permissionIDs)
            {
                if (actor.HasPermission(permId))
                {
                    hasPermission = true;
                    break;
                }
            }

            permissions.Add(new BusinessRule(ruleKey, hasPermission, description));
            return permissions.GetBrokenRules();
        }

        #endregion
    }
}